package comparator;

import java.util.ArrayList;

import parser.Constants;
import parser.IupacBranch;
import residue.AbstractResidue;
import residue.GenericComposedResidue;
import residue.GenericMonosaccharideResidue;
import residue.GenericRepeatResidue;
import residue.GenericSubstituentResidue;
import residue.Link;
import utils.TreeTools;

public class CtLinkageComparator extends AbstractComparator {
	
	

	/*Constructor*/
	public CtLinkageComparator(ArrayList<IupacBranch> branches) 
	{
		super(branches);
	}

	/*Methods*/
	public ArrayList<IupacBranch> compare()
	{
		ArrayList<IupacBranch> branchesSelected = getBranchesToCompare(); //new ArrayList<IupacBranch>();  	
		ArrayList<Link> links = getLinksToCompare(branchesSelected);
		
		/*Test on parent position*/
		try
		{
			branchesSelected = linkagePositionParentComparison(links);
			if(branchesSelected.size()==1)
			{
//				System.out.println("CtLinkageComparator compare on parent position : " + branchesSelected.get(0).getId());
				this.setBranchesCompared(branchesSelected);	
				return branchesSelected; //this.getBranchesCompared();
			}
		}
		catch(Exception ex)
		{
			System.err.println("CtLinkageComparator compare on parent position : "+ branchesSelected.get(0).getId() + " " + ex.getMessage());
		}
		
		/*Test on child position*/
		try
		{
			branchesSelected = linkagePositionChildComparison(getLinksToCompare(branchesSelected));
			if(branchesSelected.size()==1)
			{
//				System.out.println("CtLinkageComparator compare on child position : " + branchesSelected.get(0).getId());
				this.setBranchesCompared(branchesSelected);	
				return branchesSelected; //this.getBranchesCompared();
			}
		}
		catch(Exception ex)
		{
			System.err.println("CtLinkageComparator compare on child position : "+ branchesSelected.get(0).getId() + " " + ex.getMessage());
		}
		
		/*Test on parent type*/
		try
		{
			branchesSelected = linkageTypeParentComparison(getLinksToCompare(branchesSelected));
			if(branchesSelected.size()==1)
			{
//				System.out.println("CtLinkageComparator compare on parent type : " + branchesSelected.get(0).getId());
				this.setBranchesCompared(branchesSelected);	
				return branchesSelected; //this.getBranchesCompared();
			}
		}
		catch(Exception ex)
		{
			System.err.println("CtLinkageComparator compare on parent type : "+ branchesSelected.get(0).getId() + " " + ex.getMessage());
		}
		
		/*Test on child type*/
		try
		{
			branchesSelected = linkageTypeChildComparison(getLinksToCompare(branchesSelected));
			if(branchesSelected.size()==1)
			{
//				System.out.println("CtLinkageComparator compare on child position : " + branchesSelected.get(0).getId());
				this.setBranchesCompared(branchesSelected);	
				return branchesSelected; //this.getBranchesCompared();
			}
		}
		catch(Exception ex)
		{
			System.err.println("CtLinkageComparator compare on child position : "+ branchesSelected.get(0).getId() + " " + ex.getMessage());
		}
		
		
		return branchesSelected; //this.getBranchesCompared();
	}
	
	public ArrayList<Link> getLinksToCompare(ArrayList<IupacBranch> branches) 
	{
//		ArrayList<IupacBranch> branches = this.getBranchesToCompare();
		ArrayList<Link> links = new ArrayList<Link>();
		Link l = null;
		
		for(int i =0 ; i<branches.size();i++)
		{	
			/*get first abstractResidue of every branches*/
			AbstractResidue absRes = branches.get(i).getResiduesList().get(0).getAbstractResidue();
			/*test if substituent, monosach or composed.... and decompose*/
			
			if(absRes.isGenericRepeatResidue())
			{
				l = ((GenericRepeatResidue)absRes).getLinkToPrevious();
				links.add(i, l);
			}
			
			if(absRes.isGenericMonosaccharideResidue())
			{
				l = ((GenericMonosaccharideResidue)absRes).getLinkToPrevious();
				links.add(i, l);
			}
			if(absRes.isGenericSubstituentResidue())
			{
				l = ((GenericSubstituentResidue)absRes).getLinkToPrevious();
				links.add(i, l);
			}
			if(absRes.isGenericComposedResidue())
			{
				l = ((GenericComposedResidue)absRes).getMonosaccharide().getLinkToPrevious();
				links.add(i, l);
				for(int j = 0;j<((GenericComposedResidue)absRes).getSubstituents().size();j++)
				{
					((GenericComposedResidue)absRes).getSubstituents().get(j).getLinkToPrevious();
					//links.add(i, l);
				}
				
				
//				l = ((GenericComposedResidue)absRes).getMonosaccharide().getLinkToPrevious();
//				((GenericComposedResidue)absRes).getSubstituent().getLinkToPrevious();
//				links.add(i, l);
			}
		}	
		return links;
	}
	
	public ArrayList<IupacBranch> linkagePositionParentComparison(ArrayList<Link> links)
	{
		ArrayList<IupacBranch> selectedBranches = new ArrayList<IupacBranch>();
		IupacBranch branch = null;
		String ref = getMinLinkagePositionParentValue(links);
//		System.out.println("CtLinkageComparator linkagePositionParentComparison  ref : " + ref);
		
		for(int i = 0 ; i < links.size(); i++)
		{
			Link link = links.get(i);
			if(link.getRes1LinkagePosition()==ref)
			{
				/*add the branch to the ArrayList branchCompared*/
				String Res2Id = link.getRes2Id();
				branch = TreeTools.getBranchFromResidueId(Res2Id, this.getBranchesToCompare());
				selectedBranches.add(branch);
//				System.out.println("CtLinkageComparator linkagePositionParentComparison  added branch : " + branch.getId());
			}
		}
		return selectedBranches;
	}
	
	public ArrayList<IupacBranch> linkagePositionChildComparison(ArrayList<Link> links)
	{
		ArrayList<IupacBranch> selectedBranches = new ArrayList<IupacBranch>();
		IupacBranch branch = null;
		String ref = getMinLinkagePositionChildValue(links);
//		System.out.println("CtLinkageComparator linkagePositionChildComparison  ref : " + ref);
		
		for(int i = 0 ; i < links.size(); i++)
		{
			Link link = links.get(i);
			if(link.getRes2LinkagePosition()==ref)
			{
				/*add the branch to the ArrayList branchCompared*/
				branch = TreeTools.getBranchFromResidueId(link.getRes2Id(), this.getBranchesToCompare());
				selectedBranches.add(branch);
//				System.out.println("CtLinkageComparator linkagePositionChildComparison  added branch : " + branch.getId());
			}
		}
		return selectedBranches;
	}
	
	public ArrayList<IupacBranch> linkageTypeParentComparison(ArrayList<Link> links)
	{
		ArrayList<IupacBranch> selectedBranches = new ArrayList<IupacBranch>();
		IupacBranch branch = null;
		String ref = getMinLinkageTypeParentValue(links);
//		System.out.println("CtLinkageComparator linkageTypeParentComparison  ref : " + ref);
		
		for(int i = 0 ; i < links.size(); i++)
		{
			Link link = links.get(i);
//			System.out.println("CtLinkageComparator linkageTypeParentComparison  ref : " + ref);
			if(link.getRes1LinkageType()==ref)
			{
				/*add the branch to the ArrayList branchCompared*/
				branch = TreeTools.getBranchFromResidueId(link.getRes2Id(), this.getBranchesToCompare());
				selectedBranches.add(branch);
//				System.out.println("CtLinkageComparator linkageTypeParentComparison  added branch : " + branch.getId());
			}
		}
		return selectedBranches;
	}
	
	public ArrayList<IupacBranch> linkageTypeChildComparison(ArrayList<Link> links)
	{
		ArrayList<IupacBranch> selectedBranches = new ArrayList<IupacBranch>();
		IupacBranch branch = null;
		String ref = getMinLinkageTypeChildValue(links);
//		System.out.println("CtLinkageComparator linkageTypeChildComparison  ref : " + ref);
		
		for(int i = 0 ; i < links.size(); i++)
		{
			Link link = links.get(i);
			if(link.getRes2LinkageType()==ref)
			{
				/*add the branch to the ArrayList branchCompared*/
				branch = TreeTools.getBranchFromResidueId(link.getRes2Id(), this.getBranchesToCompare());
				selectedBranches.add(branch);
//				System.out.println("CtLinkageComparator linkageTypeChildComparison  added branch : " + branch.getId());
			}
		}
		return selectedBranches;
	}
	
	
	public String getMinLinkagePositionParentValue(ArrayList<Link> links)
	{
		String result;
		ArrayList<String> chars = new ArrayList<String>();
		for(int i = 0 ; i<links.size() ; i++)
		{
			chars.add(links.get(i).getRes1LinkagePosition());
		}
		result = getMinValue(chars);
		return result;
	}
	

	public String getMinLinkagePositionChildValue(ArrayList<Link> links)
	{
		ArrayList<String> chars = new ArrayList<String>();
		for(int i = 0 ; i<links.size() ; i++)
		{
			chars.add(links.get(i).getRes2LinkagePosition());
		}
		return getMinValue(chars);
	}
	
	public String getMinLinkageTypeParentValue(ArrayList<Link> links)
	{
		ArrayList<String> chars = new ArrayList<String>();
		for(int i = 0 ; i<links.size() ; i++)
		{
			chars.add(links.get(i).getRes1LinkageType());
		}
		return getMinValue(chars);
	}
	

	public String getMinLinkageTypeChildValue(ArrayList<Link> links)
	{
		ArrayList<String> chars = new ArrayList<String>();
		for(int i = 0 ; i<links.size() ; i++)
		{
			chars.add(links.get(i).getRes2LinkageType());
		}
		return getMinValue(chars);
	}
	
	public String getMinValue(ArrayList<String> chars)
	{
		String min=null;
		String temp=null;
		
		try
		{
			min=chars.get(0);
			
			for(int j = 1; j< chars.size();j++)
			{
				temp= chars.get(j);
				
				if(temp.length()==1 && Character.isDigit(temp.charAt(0)))
				{
					if((min!=Constants.UNKNOWN || min!=Constants.UNKNOWN_LINKAGE_POS) && isSmallerThan(Integer.parseInt(min.toString()), Integer.parseInt(temp.toString())))
					{
						min = temp;
					}
				}
				else if(temp==Constants.UNKNOWN || temp==Constants.UNKNOWN_LINKAGE_POS)
				{
					min = temp;
				}
			}
		}
		catch(Exception ex)
		{
			System.err.println("CtLinkageComparator getMinValue() : " + ex.getMessage());
		}
		return min;
	}
	
	public boolean isSmallerThan(int ref, int val)
	{
		boolean result = false;
		if(val<ref)
		{
			result=true;
		}
		return result;
	}
	
	public boolean isGreaterThan(int ref, int val)
	{
		boolean result = false;
		if(val>ref)
		{
			result=true;
		}
		return result;
	}
	
}
